#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

#if 0 /* 测试线程的健壮属性 */
pthread_mutex_t mutex;
pthread_mutexattr_t mattr;

void* th1(void* a)
{
  int r = pthread_mutex_lock(&mutex);
  printf("th1 r=%d\n", r);
  // 加锁后，直接退出
}

void* th2(void* a)
{
  sleep(1);
  int r = pthread_mutex_lock(&mutex);
  if (r == EOWNERDEAD) {
    printf("th2: r = EOWNERDEAD\n");
    // pthread_mutex_consistent(&mutex);
  }
  pthread_mutex_unlock(&mutex);
  printf("th2 unlocked.\n");
}

void* th3(void* a)
{
  sleep(3);
  int r = pthread_mutex_lock(&mutex);
  if (r == EOWNERDEAD) {
    printf("th3 :r = EOWNERDEAD\n");
    pthread_mutex_consistent(&mutex);
    pthread_mutex_unlock(&mutex);
    printf("th3 unlocked.\n");
  } else if (r == ENOTRECOVERABLE) {
    printf("th3 :r = ENOTRECOVERABLE\n");
  }
  else{
    pthread_mutex_unlock(&mutex);
    printf("th3 unlocked.\n");
  }
}

int main()
{
  int r;
  pthread_t pt1, pt2,pt3;

  // 设置互斥量的属性
  r = pthread_mutexattr_init(&mattr);
  assert(r == 0);
  r = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
  assert(r == 0);
  r = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);
  assert(r == 0);

  // 设置互斥量
  r = pthread_mutex_init(&mutex, &mattr);
  assert(r == 0);
  // 创建线程
  pthread_create(&pt1, NULL, th1, NULL);
  pthread_create(&pt2, NULL, th2, NULL);
  pthread_create(&pt3, NULL, th3, NULL);

  // 等待线程结束
  pthread_join(pt1, NULL);
  pthread_join(pt2, NULL);
  pthread_join(pt3, NULL);
}
#endif

#if 0 /* 测试线程信号设置共享 */
void* th1(void* a)
{
  // 选择忽略INT信号
  if (signal(SIGINT, SIG_IGN) == SIG_ERR) {
    printf("th1: ignore INT failed.\n");
  } else {
    printf("th1: OK.\n");
  }
}

void sig_int(int a)
{
  printf("INT signal.\n");
}

void* th2(void* a)
{
  // 设置新的信号处理程序
  if (signal(SIGINT, sig_int) == SIG_ERR) {
    printf("th2: set INT handler failed.\n");
  } else {
    printf("th2:OK.\n");
  }
  sleep(5);
}

sigset_t mask;

int main()
{
  int err;
  pthread_t pt1, pt2;

  err = pthread_create(&pt1, NULL, th1, NULL);
  assert(err == 0);
  // 给新线程时间设置忽略信号
  sleep(2);
  err = pthread_create(&pt2, NULL, th2, NULL);
  assert(err == 0);

  pthread_join(pt1, NULL);
  pthread_join(pt2, NULL);
  return 0;
}
#endif

sigset_t mask;

void th1_int(int a)
{
  printf("th1: get INT signal.\n");
}

void* th1(void* a)
{
  int err, signo;
  // sigset_t ma;

  // sigemptyset(&ma);
  // sigaddset(&ma, SIGQUIT);
  // pthread_sigmask(SIG_BLOCK, &ma, NULL);
  signal(SIGINT, th1_int);

  // sleep(5);
  while (1) {
    err = sigwait(&mask, &signo);
    assert(err == 0);
    switch (signo) {
      case SIGQUIT:
        printf("th1:QUIT.\n");
        break;
      default:
        printf("th1:unexcepted signal %d.\n", signo);
        break;
    }
  }
}

void* th2(void* a)
{
  int err, signo;
  sigset_t m2, old;

  sigemptyset(&m2);
  sigaddset(&m2, SIGQUIT);
  sigaddset(&m2, SIGINT); /* 额外添加INT信号 */
  err = pthread_sigmask(SIG_BLOCK, &m2, &old);
  assert(err == 0);

  // sleep(1);
  while (1) {
    err = sigwait(&m2, &signo);
    assert(err == 0);
    switch (signo) {
      case SIGINT:
        printf("th2:INT.\n");
        break;
      case SIGQUIT:
        printf("th2:QUIT.\n");
        break;
      default:
        printf("th2:unexcepted signal %d.\n", signo);
        break;
    }
  }
}

int main()
{
  int err;
  sigset_t  old;
  pthread_t pt1, pt2;

  sigemptyset(&mask);
  sigaddset(&mask, SIGQUIT);
  // sigaddset(&mask, SIGINT);
  err = pthread_sigmask(SIG_BLOCK, &mask, &old);
  assert(err == 0);

  // 创建线程
  err = pthread_create(&pt1, NULL, th1, NULL);
  assert(err == 0);
  // err = pthread_create(&pt2, NULL, th2, NULL);
  // assert(err == 0);

  // 等待线程创建完成
  sleep(1);

  // 发送信号
  // pthread_kill(pt2, SIGINT);
  // pthread_kill(pt2, SIGQUIT);
  pthread_kill(pt1, SIGQUIT);
  pthread_kill(pt1, SIGINT);

  sleep(5);

  return 0;
}